package com.igeek.boot.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.igeek.boot.entity.Shelves;
import com.igeek.boot.entity.Warehouses;
import com.igeek.boot.exception.WisdomFactoryException;
import com.igeek.boot.mapper.WarehousesMapper;
import com.igeek.boot.service.IShelvesService;
import com.igeek.boot.service.IWarehousesService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.igeek.boot.utils.LocationUtils;
import com.igeek.boot.vo.PageQueryVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.geo.Point;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author jwj
 * @since 2023-12-26
 */
@Service
@Slf4j
public class WarehousesServiceImpl extends ServiceImpl<WarehousesMapper, Warehouses> implements IWarehousesService {

    //geo的key
    private static final String LOCATION_KEY = "gaode::location";
    //geo的member
    private static final String LOCATION_MEMBER = "member::";
    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private IShelvesService shelvesService;

    @Autowired
    private LocationUtils locationUtils;

    @Autowired
    private WarehousesMapper warehousesMapper;
    //分页查询仓库表的数据
    @Override
    @Transactional(readOnly = true)
    //@Cacheable(cacheNames = "Warehouses",keyGenerator = "keyGenerator")
    public Page<Warehouses> findPage(PageQueryVO pageQueryVO) {
        //获取分页条件
        Integer currentPage = pageQueryVO.getCurrentPage();
        Integer pageSize = pageQueryVO.getPageSize();
        Page<Warehouses> page = new Page<>(currentPage, pageSize);

        //封装查询条件  查询的信息可能根据仓库名称、仓库类型、仓库的城市进行查询
        LambdaQueryWrapper<Warehouses> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        String queryString = pageQueryVO.getQueryString();
        lambdaQueryWrapper.or().like(StringUtils.hasLength(queryString), Warehouses::getWarehouseName, queryString)
                .or().like(StringUtils.hasLength(queryString), Warehouses::getWarehouseType, queryString)
               .or().like(StringUtils.hasLength(queryString), Warehouses::getCity, queryString);

        //执行查询
        Page<Warehouses> warehousesPage = baseMapper.selectPage(page, lambdaQueryWrapper);
        log.info("查询仓库表的数据{}",warehousesPage.getRecords());
        return warehousesPage;
    }

    //查询仓库表的所有数据
    @Override
    @Transactional
    public List<Warehouses> findAll() {
        List<Warehouses> warehousesList = baseMapper.selectList(null);
        //将所有的坐标存入redis缓存中
        return warehousesList;
    }

    //将数据库所有的仓库坐标存入Redis中
    @Override
    @Transactional
    public boolean saveAllLocation() {
        //1.先获取到数据库中所有的仓库信息
        List<Warehouses> warehousesList = baseMapper.selectList(null);
        if(warehousesList!= null && warehousesList.size() > 0){
            warehousesList.forEach(this::addLocationToRedis);
        }
        return true;
    }

    //将传入的warehouses存入Redis中
    @Transactional
    public boolean addLocationToRedis(Warehouses warehouses){
        log.info("将仓库的坐标存入Redis中");
        //2.获取到每个仓库的坐标信息
        Map<String, String> params = new HashMap<>();
        params.put("address", warehouses.getAddressDetail());
        params.put("city", warehouses.getCity());
        try{
            JSONObject map = locationUtils.getLocation(params);
            log.info("获取到坐标信息{}",map);
            //3.将坐标信息存入redis缓存中
            if (map != null) {
                //将location的坐标分隔开
                String[] split = map.getString("location").split(",");
                String formatted_address = map.getString("formatted_address");
                warehouses.setLocation(formatted_address);
                warehouses.setCity(map.getString("city"));
                warehouses.setAddressDetail(map.getString("district"));
                String keyName = LOCATION_MEMBER+warehouses.getCity()+warehouses.getAddressDetail()+warehouses.getWarehouseName();
                //判断当前城市是否已经存在
                List<String> members = redisTemplate.opsForGeo().position(LOCATION_KEY, keyName);
                if (members.get(0) != null && members.size() > 0) {
                    log.info("该地理位置已经存在");
                    return false;
                } else{
                    //不存在存入Redis中
                    redisTemplate.opsForGeo().add(LOCATION_KEY, new Point(Double.parseDouble(split[0]), Double.parseDouble(split[1])), keyName);
                    return true;
                }
            }
        }catch(Exception e){
            e.printStackTrace();
            return false;
        }
        return false;
    }

    //添加仓库 并将仓库的坐标信息填入Redis中
    @Override
    @Transactional
    public boolean add(Warehouses warehouses) {
        //如果存入Redis成功就向数据库中添加
        if(addLocationToRedis(warehouses)){
            return baseMapper.insert(warehouses) > 0;
        }
        return false;
    }

    //删除仓库信息
    @Transactional
    @Override
    public boolean delWarehouses(Integer id) {
        //1.首先检查该仓库是否为空： 检查是否存在货架信息
        List<Shelves> allByWarehouseId = shelvesService.findAllByWarehouseId(id);
        //2.当货架不存在的时候进行删除，否则不删除
        if(CollectionUtils.isEmpty(allByWarehouseId)){
            //删除Redis中的坐标GEO  先判断是否有该坐标信息
            Warehouses warehouses = baseMapper.selectById(id);
            String keyName = LOCATION_MEMBER+warehouses.getCity()+warehouses.getAddressDetail()+warehouses.getWarehouseName();
            List position = redisTemplate.opsForGeo().position(LOCATION_KEY,keyName);
            if(position!=null && position.size()>0){//存在该坐标信息  删除Redis并且删除数据库的信息
                redisTemplate.opsForGeo().remove(LOCATION_KEY,keyName);
                return baseMapper.deleteById(id)>0;
            }
        }
        return false;
    }

    //修改仓库信息
    @Override
    @Transactional
    public boolean updateWarehouses(Warehouses warehouses) {
        //进行修改Redis中的坐标信息
        //1.根据ID查询仓库的原始信息，然后再根据原始的信息进行更新Redis
        Warehouses oldWarehouses = baseMapper.selectById(warehouses.getWarehouseID());
        //2.如果存在该坐标信息删除Redis中的仓库坐标
        String oldKeyName = LOCATION_MEMBER+oldWarehouses.getCity()+oldWarehouses.getAddressDetail()+oldWarehouses.getWarehouseName();
        List position = redisTemplate.opsForGeo().position(LOCATION_KEY, oldKeyName);
        if(position.get(0)!=null){
            redisTemplate.opsForGeo().remove(LOCATION_KEY,oldKeyName);
        }
        //3.重新存入仓库坐标
        String newKeyName = LOCATION_MEMBER+warehouses.getCity()+warehouses.getAddressDetail()+warehouses.getWarehouseName();
        boolean flag = addLocationToRedis(warehouses);
        //4.进行跟新数据库的数据信息
        if(flag&&baseMapper.updateById(warehouses)>0){
            return true;
        }
        return false;
    }

    //查询仓库的详细信息
    @Override
    @Transactional(readOnly = true)
    public Warehouses findOneDetail(Integer id) {
        return warehousesMapper.findOneDetail(id);
    }
    //根据id查询仓库的信息
    @Transactional(readOnly = true)
    public Warehouses findOneById(Integer id){
        return warehousesMapper.selectById(id);
    }

    //根据id查询仓库的位置坐标
    @Override
    @Transactional(readOnly = true)
    public String findOneLocation(Integer id) {
        //1.查询用户的信息
        Warehouses warehouses = warehousesMapper.selectById(id);
        //2.获取Redis查询条件
        try{
            if(warehouses!=null){
                String keyName = LOCATION_MEMBER+warehouses.getCity()+warehouses.getAddressDetail()+warehouses.getWarehouseName();
                List position = redisTemplate.opsForGeo().position(LOCATION_KEY, keyName);
                if(position.get(0)!=null){
                    Point point = (Point) position.get(0);
                    return point.getX()+","+point.getY();
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }

    //获取仓库的所有仓库名称和坐标信息
    @Override
    @Transactional(readOnly = true)
    public List<Map<String, Object>> findAllLocationAndName() {
        //查询仓库的所有信息
        List<Warehouses> list = findAll();
        List<Map<String, Object>> mapList = list.stream().map(warehouses -> {
            Map<String, Object> map = new HashMap<>();
            //获取仓库的坐标信息
            String point = findOneLocation(warehouses.getWarehouseID());
            String name = warehouses.getWarehouseName();
            //将仓库的坐标信息和仓库的名称存入map中
            map.put("point", point);
            map.put("name", name);
            return map;
        }).collect(Collectors.toList());
        return mapList;
    }
}
